package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.feign.search.SearchFeignClient;
import com.atguigu.gmall.item.to.CategoryView;
import com.atguigu.gmall.product.entity.*;
import com.atguigu.gmall.product.mapper.SkuInfoMapper;
import com.atguigu.gmall.product.service.*;
import com.atguigu.gmall.product.vo.SaveSkuVo;
import com.atguigu.gmall.search.Goods;
import com.atguigu.gmall.search.SearchAttr;
import com.atguigu.starter.cache.service.Bitmapservice;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
* @author lyd
* @description 针对表【sku_info(库存单元表)】的数据库操作Service实现
* @createDate 2023-08-15 13:49:56
*/
@Service
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo>
    implements SkuInfoService{

    @Autowired
    private SkuImageService skuImageService;
    @Autowired
    private SkuAttrValueService skuAttrValueService;

    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private Bitmapservice bitmapservice;

    @Autowired
    private SearchFeignClient searchFeignClient;
    @Autowired
    private BaseTrademarkServiceImpl baseTrademarkService;

    @Autowired
    private BaseCategory1Service baseCategory1Service;

    @Autowired
    private BaseAttrValueService baseAttrValueService;
    @Autowired
    private ThreadPoolExecutor executor;
    @Override
    public void saveSkuInfo(SaveSkuVo vo) {
        //1.向sku_info表中插入数据
        SkuInfo skuInfo = new SkuInfo();
        BeanUtils.copyProperties(vo,skuInfo);
        this.save(skuInfo);

        Long skuId = skuInfo.getId();
        //2.向sku_image插入数据
        List<SkuImage> skuImageList = vo.getSkuImageList().stream()
                .map(item -> {
                    SkuImage skuImage = new SkuImage();
                    skuImage.setSkuId(skuId);
                    skuImage.setImgName(item.getImgName());
                    skuImage.setImgUrl(item.getImgUrl());
                    skuImage.setSpuImgId(item.getSpuImgId());
                    skuImage.setIsDefault(item.getIsDefault());
                    return skuImage;
                }).collect(Collectors.toList());
        skuImageService.saveBatch(skuImageList);

        //3.向sku_attr_value表插入数据
        List<SkuAttrValue> skuAttrValueList = vo.getSkuAttrValueList().stream()
                .map(item -> {
                    SkuAttrValue skuAttrValue = new SkuAttrValue();
                    skuAttrValue.setAttrId(item.getAttrId());
                    skuAttrValue.setValueId(item.getValueId());
                    skuAttrValue.setSkuId(skuId);
                    return skuAttrValue;
                }).collect(Collectors.toList());
        skuAttrValueService.saveBatch(skuAttrValueList);


        //4.向sku_sale_attr_value表插入数据
        List<SkuSaleAttrValue> skuSaleAttrValueList = vo.getSkuSaleAttrValueList().stream()
                .map(item -> {
                    SkuSaleAttrValue skuSaleAttrValue = new SkuSaleAttrValue();
                    skuSaleAttrValue.setSkuId(skuId);
                    skuSaleAttrValue.setSpuId(vo.getSpuId());
                    skuSaleAttrValue.setSaleAttrValueId(item.getSaleAttrValueId());
                    return skuSaleAttrValue;
                }).collect(Collectors.toList());
        skuSaleAttrValueService.saveBatch(skuSaleAttrValueList);

    }

    /**
     * 使用大位数组的方式，全量缓存skuId在redis中
     */
    @Override
    public void initAllSkuId() {
        List<Long> skuIdList = this.lambdaQuery()
                .select(SkuInfo::getId)
                .list()
                .stream()
                .map(SkuInfo::getId)
                .collect(Collectors.toList());
        skuIdList.forEach(item->{
            redisTemplate.opsForValue().setBit(RedisConst.BITMAP_SKUIDS,item,true);
        });
    }

    /**
     * 商品上架分三部
     *  1、更新数据库的数据
     *  2、商品需要添加到位图
     *  3、把商品保存在es
     * @param skuId
     */
    @Override
    public void onSale(Long skuId) {
        // 1、更新数据库的数据
        this.lambdaUpdate()
                .set(SkuInfo::getIsSale,1)
                .eq(SkuInfo::getId,skuId)
                .update();
        //2、商品上架要添加到位图中
        bitmapservice.setbit(RedisConst.BITMAP_SKUIDS, skuId, true);
        //3、把商品数据保存在es中
        Goods goods = prepareGoods(skuId);
        searchFeignClient.save(goods);
    }

    /**
     * 商品下架分为三部分
     *  1、更新数据库的数据
     *  2、商品需要从位图中删除
     *  3、从es中删除商品
     * @param skuId
     */
    @Override
    public void cancelSale(Long skuId) {
        //1、更新数据库的数据
        this.lambdaUpdate()
                .set(SkuInfo::getIsSale,0)
                .eq(SkuInfo::getId,skuId)
                .update();
        //2、商品下架要从位图中删除
        bitmapservice.setbit(RedisConst.SKU_INFO_CACHE_KEY,skuId,false);
        //3、把商品从es中移除
        searchFeignClient.deleteGoods(skuId);
        //3、删除redis中缓存的数据，保证缓存中数据一致性的问题
    }

    /**
     * 封装es查询商品数据的格式
     * @param skuId
     * @return
     */
    private Goods prepareGoods(Long skuId) {
        //3、把商品的数据保存在es
        Goods goods = new Goods();
        //3.1保存goods的基本信息
        CompletableFuture<SkuInfo> skuInfoFuture = CompletableFuture.supplyAsync(() -> {
            SkuInfo skuInfo = this.getById(skuId);
            goods.setId(skuInfo.getId());
            goods.setDefaultImg(skuInfo.getSkuDefaultImg());
            goods.setTitle(skuInfo.getSkuName());
            goods.setPrice(skuInfo.getPrice());
            goods.setCreateTime(new Date());
            return skuInfo;
        }, executor);


        //3.2保存商品品牌的信息
        CompletableFuture<Void> tradeMarkFuture = skuInfoFuture.thenAcceptAsync((result) -> {
            BaseTrademark trademark = baseTrademarkService.getById(result.getTmId());
            goods.setTmId(trademark.getId());
            goods.setTmName(trademark.getTmName());
            goods.setTmLogoUrl(trademark.getLogoUrl());
        }, executor);


        //3.3保存三级分类信息
        CompletableFuture<Void> categoryFuture = skuInfoFuture.thenAcceptAsync((result) -> {
            CategoryView categoryView = baseCategory1Service.getCategoryView(result.getCategory3Id());
            goods.setCategory1Id(categoryView.getCategory1Id());
            goods.setCategory1Name(categoryView.getCategory1Name());
            goods.setCategory2Id(categoryView.getCategory2Id());
            goods.setCategory2Name(categoryView.getCategory2Name());
            goods.setCategory3Id(categoryView.getCategory3Id());
            goods.setCategory3Name(categoryView.getCategory3Name());
            goods.setHotScore(0L);
        }, executor);

        //3.4保存搜索的平台属性
        CompletableFuture<Void> searchAttrFuture = CompletableFuture.runAsync(() -> {
            List<SearchAttr> searchAttrs = baseAttrValueService.getAttrValues(skuId);
            goods.setAttrs(searchAttrs);
        }, executor);
        CompletableFuture.allOf(tradeMarkFuture,categoryFuture,searchAttrFuture)
                .join();
        return goods;
    }
}




